#include <xen/errno.h>
#include <xen/delay.h>
#include <xen/cpumask.h>
+#include <xen/list.h>
#include <xen/sched.h>
#include <xen/timer.h>
#include <xen/xmalloc.h>
#include <acpi/acpi.h>
#include <acpi/cpufreq/cpufreq.h>
-/* TODO: change to link list later as domain number may be sparse */
-static cpumask_t cpufreq_dom_map[NR_CPUS];
+struct cpufreq_dom {
+ unsigned int dom;
+ cpumask_t map;
+ struct list_head node;
+};
+static LIST_HEAD(cpufreq_dom_list_head);
int cpufreq_limit_change(unsigned int cpu)
{
{
int ret = 0;
unsigned int firstcpu;
- unsigned int dom;
+ unsigned int dom, domexist = 0;
unsigned int j;
+ struct list_head *pos;
+ struct cpufreq_dom *cpufreq_dom;
struct cpufreq_policy new_policy;
struct cpufreq_policy *policy;
struct processor_performance *perf = &processor_pminfo[cpu]->perf;
/* to protect the case when Px was not controlled by xen */
- if (!processor_pminfo[cpu] || !(perf->init & XEN_PX_INIT))
- return 0;
-
- if (!cpu_online(cpu) || cpufreq_cpu_policy[cpu])
+ if (!processor_pminfo[cpu] ||
+ !(perf->init & XEN_PX_INIT) ||
+ !cpu_online(cpu))
return -EINVAL;
+ if (cpufreq_cpu_policy[cpu])
+ return 0;
+
ret = cpufreq_statistic_init(cpu);
if (ret)
return ret;
dom = perf->domain_info.domain;
- if (cpus_weight(cpufreq_dom_map[dom])) {
+
+ list_for_each(pos, &cpufreq_dom_list_head) {
+ cpufreq_dom = list_entry(pos, struct cpufreq_dom, node);
+ if (dom == cpufreq_dom->dom) {
+ domexist = 1;
+ break;
+ }
+ }
+
+ if (domexist) {
/* share policy with the first cpu since on same boat */
- firstcpu = first_cpu(cpufreq_dom_map[dom]);
+ firstcpu = first_cpu(cpufreq_dom->map);
policy = cpufreq_cpu_policy[firstcpu];
cpufreq_cpu_policy[cpu] = policy;
- cpu_set(cpu, cpufreq_dom_map[dom]);
+ cpu_set(cpu, cpufreq_dom->map);
cpu_set(cpu, policy->cpus);
printk(KERN_EMERG"adding CPU %u\n", cpu);
} else {
+ cpufreq_dom = xmalloc(struct cpufreq_dom);
+ if (!cpufreq_dom) {
+ cpufreq_statistic_exit(cpu);
+ return -ENOMEM;
+ }
+ memset(cpufreq_dom, 0, sizeof(struct cpufreq_dom));
+ cpufreq_dom->dom = dom;
+ cpu_set(cpu, cpufreq_dom->map);
+ list_add(&cpufreq_dom->node, &cpufreq_dom_list_head);
+
/* for the first cpu, setup policy and do init work */
policy = xmalloc(struct cpufreq_policy);
if (!policy) {
+ list_del(&cpufreq_dom->node);
+ xfree(cpufreq_dom);
cpufreq_statistic_exit(cpu);
return -ENOMEM;
}
memset(policy, 0, sizeof(struct cpufreq_policy));
-
- cpufreq_cpu_policy[cpu] = policy;
- cpu_set(cpu, cpufreq_dom_map[dom]);
+ policy->cpu = cpu;
cpu_set(cpu, policy->cpus);
+ cpufreq_cpu_policy[cpu] = policy;
- policy->cpu = cpu;
ret = cpufreq_driver->init(policy);
if (ret)
goto err1;
* After get full cpumap of the coordination domain,
* we can safely start gov here.
*/
- if (cpus_weight(cpufreq_dom_map[dom]) ==
+ if (cpus_weight(cpufreq_dom->map) ==
perf->domain_info.num_processors) {
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
policy->governor = NULL;
err2:
cpufreq_driver->exit(policy);
err1:
- for_each_cpu_mask(j, cpufreq_dom_map[dom]) {
+ for_each_cpu_mask(j, cpufreq_dom->map) {
cpufreq_cpu_policy[j] = NULL;
cpufreq_statistic_exit(j);
}
- cpus_clear(cpufreq_dom_map[dom]);
+ list_del(&cpufreq_dom->node);
+ xfree(cpufreq_dom);
xfree(policy);
return ret;
}
int cpufreq_del_cpu(unsigned int cpu)
{
- unsigned int dom;
+ unsigned int dom, domexist = 0;
+ struct list_head *pos;
+ struct cpufreq_dom *cpufreq_dom;
struct cpufreq_policy *policy;
struct processor_performance *perf = &processor_pminfo[cpu]->perf;
/* to protect the case when Px was not controlled by xen */
- if (!processor_pminfo[cpu] || !(perf->init & XEN_PX_INIT))
- return 0;
-
- if (!cpu_online(cpu) || !cpufreq_cpu_policy[cpu])
+ if (!processor_pminfo[cpu] ||
+ !(perf->init & XEN_PX_INIT) ||
+ !cpu_online(cpu))
return -EINVAL;
+ if (!cpufreq_cpu_policy[cpu])
+ return 0;
+
dom = perf->domain_info.domain;
policy = cpufreq_cpu_policy[cpu];
- printk(KERN_EMERG"deleting CPU %u\n", cpu);
+ list_for_each(pos, &cpufreq_dom_list_head) {
+ cpufreq_dom = list_entry(pos, struct cpufreq_dom, node);
+ if (dom == cpufreq_dom->dom) {
+ domexist = 1;
+ break;
+ }
+ }
+
+ if (!domexist)
+ return -EINVAL;
/* for the first cpu of the domain, stop gov */
- if (cpus_weight(cpufreq_dom_map[dom]) ==
+ if (cpus_weight(cpufreq_dom->map) ==
perf->domain_info.num_processors)
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
cpufreq_cpu_policy[cpu] = NULL;
cpu_clear(cpu, policy->cpus);
- cpu_clear(cpu, cpufreq_dom_map[dom]);
+ cpu_clear(cpu, cpufreq_dom->map);
cpufreq_statistic_exit(cpu);
/* for the last cpu of the domain, clean room */
/* It's safe here to free freq_table, drv_data and policy */
- if (!cpus_weight(cpufreq_dom_map[dom])) {
+ if (!cpus_weight(cpufreq_dom->map)) {
cpufreq_driver->exit(policy);
+ list_del(&cpufreq_dom->node);
+ xfree(cpufreq_dom);
xfree(policy);
}
+ printk(KERN_EMERG"deleting CPU %u\n", cpu);
return 0;
}